package com.eet.struts.snmp.util;

import lombok.extern.slf4j.Slf4j;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * snmp工具类
 *
 * @author Administrator
 */
@Slf4j
public class SnmpUtils {

    /**
     * 创建团体目标实体
     *
     * @param ip        IP
     * @param community 团体
     * @param port      端口
     * @return 团体实体
     */
    public static CommunityTarget createDefault(String ip, String community, int port) {
        if (StringUtils.isEmpty(ip)) {
            throw new NullPointerException("ip is null");
        }
        if (StringUtils.isEmpty(community)) {
            throw new NullPointerException("community is null");
        }

        Address address = GenericAddress.parse("udp:" + ip + "/" + port);
        CommunityTarget target = new CommunityTarget();
        target.setCommunity(new OctetString(community));
        target.setAddress(address);
        target.setVersion(SnmpConstants.version2c);
        target.setTimeout(3000);
        target.setRetries(5);
        return target;
    }

    /**
     * 获取SNMP数据信息
     *
     * @param ip        IP地址
     * @param community 团体
     * @param port      端口
     * @param oid       OID
     * @return 数据列表
     */
    public static List<Map<String, String>> snmpGet(String ip, String community, int port, String oid) {
        if (StringUtils.isEmpty(ip)) {
            throw new NullPointerException("ip is null");
        }
        if (StringUtils.isEmpty(community)) {
            throw new NullPointerException("community is null");
        }

        List<Map<String, String>> list = null;
        CommunityTarget target = createDefault(ip, community, port);
        Snmp snmp = null;
        try {
            PDU pdu = new PDU();
            pdu.add(new VariableBinding(new OID(oid)));
            DefaultUdpTransportMapping transport = new DefaultUdpTransportMapping();
            snmp = new Snmp(transport);
            snmp.listen();

            pdu.setType(PDU.GET);
            ResponseEvent event = snmp.send(pdu, target);

            PDU response = event.getResponse();

            if (response != null && response.size() > 0) {
                list = new ArrayList<>();
                for (VariableBinding vb : response.getVariableBindings()) {
                    Map<String, String> map = new HashMap<>(8);
                    map.put(oid, vb.toValueString());
                    list.add(map);
                }
            }
        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            closeSnmp(snmp);
        }
        return list;
    }

    /**
     * 关流
     *
     * @param snmp SNMP实体
     */
    public static void closeSnmp(Snmp snmp) {
        try {
            if (snmp != null) {
                snmp.close();
            }
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 批量获取SNMP信息
     *
     * @param ip        IP
     * @param community 团体
     * @param port      端口
     * @param oidList   OID集合
     */
    public static void snmpGetList(String ip, String community, int port, List<String> oidList) {
        if (StringUtils.isEmpty(ip)) {
            throw new NullPointerException("ip is null");
        }
        if (StringUtils.isEmpty(community)) {
            throw new NullPointerException("community is null");
        }
        if (CollectionUtils.isEmpty(oidList)) {
            throw new NullPointerException("oidList is null");
        }

        CommunityTarget target = createDefault(ip, community, port);
        Snmp snmp = null;
        try {
            PDU pdu = new PDU();

            for (String oid : oidList) {
                pdu.add(new VariableBinding(new OID(oid)));
            }

            DefaultUdpTransportMapping transport = new DefaultUdpTransportMapping();
            snmp = new Snmp(transport);
            snmp.listen();

            pdu.setType(PDU.GET);
            ResponseEvent event = snmp.send(pdu, target);
            PDU response = event.getResponse();
            if (response != null && response.size() > 0) {
                for (VariableBinding vb : response.getVariableBindings()) {
                    log.info(vb.getOid() + "=" + vb.getVariable());
                }
            }
        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            closeSnmp(snmp);
        }
    }

    public static void snmpAsyncGetList(String ip, String community, int port, List<String> oidList) {
        if (StringUtils.isEmpty(ip)) {
            throw new NullPointerException("ip is null");
        }
        if (StringUtils.isEmpty(community)) {
            throw new NullPointerException("community is null");
        }
        if (CollectionUtils.isEmpty(oidList)) {
            throw new NullPointerException("oidList is null");
        }

        CommunityTarget target = createDefault(ip, community, port);
        Snmp snmp = null;
        try {
            PDU pdu = new PDU();

            for (String oid : oidList) {
                pdu.add(new VariableBinding(new OID(oid)));
            }

            DefaultUdpTransportMapping transport = new DefaultUdpTransportMapping();
            snmp = new Snmp(transport);
            snmp.listen();
            pdu.setType(PDU.GET);

            /*
             * 异步获取
             */
            ResponseListener listener = new ResponseListener() {
                @Override
                public void onResponse(ResponseEvent event) {
                    Snmp source = (Snmp) event.getSource();
                    source.cancel(event.getRequest(), this);
                    PDU response = event.getResponse();
                    if (response != null && response.size() > 0) {

                    }
                }
            };
        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            closeSnmp(snmp);
        }
    }
}
